package com.face.recognition.service.impl;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.enums.ImageFormat;
import com.arcsoft.face.toolkit.ImageInfo;
import com.face.recognition.domain.*;
import com.face.recognition.mapper.FaceRecognitionMapper;
import com.face.recognition.service.FaceRecognitionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;

@Service
public class FaceRecognitionServiceImpl implements FaceRecognitionService {

    FaceEngine faceEngine = new FaceEngine();
    {
        // 引擎配置
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setDetectFaceScaleVal(32);

        // 功能配置
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        //是否支持人脸检测
        functionConfiguration.setSupportFaceDetect(true);
        //是否支持人脸识别
        functionConfiguration.setSupportFaceRecognition(true);
        //是否支持RGB活体检测
        functionConfiguration.setSupportLiveness(true);
        //设置引擎功能配置
        engineConfiguration.setFunctionConfiguration(functionConfiguration);

        // 初始化引擎
        int initCode = faceEngine.init(engineConfiguration);

        if (initCode != ErrorInfo.MOK.getValue()) {
            System.out.println("初始化引擎失败");
        } else {
            System.out.println("初始化引擎成功");
        }
    }

    @Autowired
    private FaceRecognitionMapper faceRecognitionMapper;

    //获取数据库中所有的人脸信息
    @Override
    public List<UserFaceInfo> getAllFace() {

        return faceRecognitionMapper.getAllFace();
    }

    //获取指定id的人脸信息
    @Override
    public UserFaceInfo getFace(String id) {

        return faceRecognitionMapper.getFace(id);
    }

    //保存人脸信息
    @Override
    public void saveFace(UserFaceInfo userFaceInfo) {

        faceRecognitionMapper.saveFace(userFaceInfo);
    }

    //获取人脸特征值
    @Override
    public UserFaceFeature getFaceFeature(File faceImage) {

        UserFaceFeature userFaceFeature = new UserFaceFeature();

        //人脸检测
        ImageInfo imageInfo = getRGBData(faceImage);
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
        int detectCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList);
        //人脸检测失败的情况
        if(detectCode != ErrorInfo.MOK.getValue()) {
            userFaceFeature.setCode(detectCode);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }
        //无人脸的情况
        if(faceInfoList == null || faceInfoList.size()==0) {
            userFaceFeature.setCode(300);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }
        //多个人脸的情况
        if(faceInfoList.size()!=1) {
            userFaceFeature.setCode(350);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }

        //人脸属性检测（调用process）
        FunctionConfiguration configuration = new FunctionConfiguration();
        configuration.setSupportLiveness(true);
        int processCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList, configuration);
        //人脸属性检测失败的情况
        if(processCode != ErrorInfo.MOK.getValue()) {
            userFaceFeature.setCode(processCode);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }

        //活体检测
        List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
        int livenessCode = faceEngine.getLiveness(livenessInfoList);
        //活体检测失败的情况
        if(livenessCode != ErrorInfo.MOK.getValue()) {
            userFaceFeature.setCode(livenessCode);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }
        //未知=-1 、非活体=0 、活体=1、超出人脸=-2
        if(livenessInfoList.get(0).getLiveness()!=1) {
            userFaceFeature.setCode(400 + livenessInfoList.get(0).getLiveness());
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }

        //特征提取
        FaceFeature faceFeature = new FaceFeature();
        int extractCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, faceInfoList.get(0), faceFeature);
        //特征提取失败的情况
        if(extractCode != ErrorInfo.MOK.getValue()) {
            userFaceFeature.setCode(extractCode);
            userFaceFeature.setFeatureValue(null);
            return userFaceFeature;
        }
        //特征提取成功的情况
        userFaceFeature.setCode(200);
        userFaceFeature.setFeatureValue(faceFeature.getFeatureData());
        return userFaceFeature;
    }

    //人脸比对
    @Override
    public UserFaceCompare compareFace(byte[] face1, byte[] face2) {

        UserFaceCompare userFaceCompare = new UserFaceCompare();

        //特征比对
        FaceFeature targetFaceFeature = new FaceFeature();
        targetFaceFeature.setFeatureData(face1);
        FaceFeature sourceFaceFeature = new FaceFeature();
        sourceFaceFeature.setFeatureData(face2);
        FaceSimilar faceSimilar = new FaceSimilar();
        int compareCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
        //人脸比对失败的情况
        if(compareCode != ErrorInfo.MOK.getValue()) {
            userFaceCompare.setCode(compareCode);
            userFaceCompare.setScore(-1);
            return userFaceCompare;
        }
        //人脸比对成功的情况
        userFaceCompare.setCode(200);
        userFaceCompare.setScore(faceSimilar.getScore());
        return userFaceCompare;
    }

    //人脸注册
    @Override
    public FaceRecognitionResponse register(File registerImage, String id) {

        FaceRecognitionResponse faceRecognitionResponse = new FaceRecognitionResponse();
        //提取特征值
        UserFaceFeature userFaceFeature = getFaceFeature(registerImage);
        if(userFaceFeature.getCode() == 200) {
            //保存特征值至数据库
            UserFaceInfo userFaceInfo = new UserFaceInfo();
            userFaceInfo.setUserId(id);
            userFaceInfo.setFaceFeatureValue(userFaceFeature.getFeatureValue());
            userFaceInfo.setGmtCreate(new Date());
            saveFace(userFaceInfo);

            faceRecognitionResponse.setCode(200);
            faceRecognitionResponse.setMsg("注册成功！");
        } else {
            registerImage.delete();
            faceRecognitionResponse.setCode(userFaceFeature.getCode());
            faceRecognitionResponse.setMsg("注册失败！请查询错误码！");
        }

        return faceRecognitionResponse;
    }

    //人脸签到
    @Override
    public FaceRecognitionResponse signIn(File signInImage) {

        FaceRecognitionResponse faceRecognitionResponse = new FaceRecognitionResponse();

        //提取多人脸特征值
        UserFaceFeature userFaceFeature = getFaceFeature(signInImage);
        if (userFaceFeature.getCode() == 200) {
            UserFaceCompare userFaceCompare;
            //获取数据库中所有的人脸信息
            List<UserFaceInfo> userFaceInfoList = getAllFace();
            for (UserFaceInfo storedFace : userFaceInfoList) {
                //人脸比对
                userFaceCompare = compareFace(userFaceFeature.getFeatureValue(), storedFace.getFaceFeatureValue());
                if (userFaceCompare.getCode() == 200) {
                    //超过0.8即认为比对成功
                    if (userFaceCompare.getScore() > 0.8) {
                        String newId = storedFace.getUserId();
                        faceRecognitionResponse.setCode(200);
                        faceRecognitionResponse.setMsg(newId + "签到成功！");
                        System.out.println(newId + "签到成功！");
                        signInImage.renameTo(new File("D:\\FaceImg\\SignIn", newId + "_RegisterImage.jpg"));
                        return faceRecognitionResponse;
                    }
                }
            }
            faceRecognitionResponse.setCode(550);
            faceRecognitionResponse.setMsg("签到失败！请查询错误码！");
        } else {
            faceRecognitionResponse.setCode(userFaceFeature.getCode());
            faceRecognitionResponse.setMsg("签到失败！请查询错误码！");
            //return signInResponse;
        }
        return faceRecognitionResponse;
    }


}
